package com.zz.ecommerce.common.xml.util;

import com.zz.ecommerce.common.WebserviceException;
import com.zz.ecommerce.common.xml.TMessageType;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2015-12-18.
 */
@Component
public class XmlUtil {

    private static final Logger LOG = LoggerFactory.getLogger(XmlUtil.class);

    private final static String ENCODING = "UTF-8";

    @Value("${jinanCustTransId}")
    private String _jinanCustTransId;
    public static String JINAN_CUST_TRANS_ID;

    @Value("${qingdaoCustTransId}")
    private String _qingdaoCustTransId;
    public static String QINGDAO_CUST_TRANS_ID;

    @Value("${inspTransId}")
    private String _inspTransId;
    public static String INSP_TRANS_ID;

    @Autowired
    private XmlDao _xmlDao;
    private static XmlDao XML_DAO;

    @PostConstruct
    public void init() {
        JINAN_CUST_TRANS_ID = _jinanCustTransId;
        QINGDAO_CUST_TRANS_ID = _qingdaoCustTransId;
        INSP_TRANS_ID = _inspTransId;
        XML_DAO = _xmlDao;
    }

    private static File createFile(String transId, String fileName) {
        if(StringUtils.isEmpty(transId))
        {
            throw new RuntimeException("transId不存在");
        }

        String localPath = XML_DAO.getLocalPath(transId);
        File dir = new File(localPath);
        if (!dir.isDirectory()) {
            dir.mkdirs();
        }
        String fullFileName = localPath + "/" + fileName;

        File file = new File(fullFileName);
        LOG.debug("file:" + file.getAbsolutePath());

        return file;
    }

    public static <T> void toCustXMLFile(T bean) throws Exception {

        String fileName = BeanUtils.getProperty(bean, "fileName");

        String xml = toXML(bean);

        toXMLFile(getCustSendPath(bean), fileName, xml);

        String messageId = BeanUtils.getProperty(bean, "messageId");
        logXml(messageId, xml, TMessageType.TO_CUST);
    }

    public static <T> void toCustXMLFile(T bean, String relateMessageId) throws Exception {

        String fileName = BeanUtils.getProperty(bean, "fileName");
        String xml = toXML(bean);

        toXMLFile(getCustSendPath(bean), fileName, xml);

        String messageId = BeanUtils.getProperty(bean, "messageId");
        logXml(messageId, relateMessageId, xml, TMessageType.TO_CUST);
    }

    public static <T> void toInspXMLFile(T bean) throws Exception {

        String fileName = BeanUtils.getProperty(bean, "fileName");
        String xml = toXML(bean);

        toXMLFile(INSP_TRANS_ID, fileName, xml);

        String messageId = BeanUtils.getProperty(bean, "messageId");
        logXml(messageId, xml, TMessageType.TO_INSP);
    }

    public static void logXml(String messageId, String xml, TMessageType type) {
        XML_DAO.logXml(messageId, xml, type.value());
    }

    public static void logXml(String messageId, String relateMessageId, String xml, TMessageType type) {
        relateMessageId = StringUtils.defaultString(relateMessageId);
        XML_DAO.logRelateXml(messageId, relateMessageId, xml, type.value());
    }

    public static <T> void toXMLFile(String sendId, String fileName, String xml) throws Exception {

        BufferedOutputStream out = null;
        try {
            File file = createFile(sendId, fileName);
            out = new BufferedOutputStream(new FileOutputStream(file));
            out.write(xml.getBytes(ENCODING));
            out.flush();
        } catch (Exception e) {
            LOG.error("保存文件失败", e);
            throw e;
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    public static <T> String toXML(T bean) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(bean.getClass());
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.setProperty(Marshaller.JAXB_ENCODING, ENCODING);

        StringWriter writer = new StringWriter();
        m.marshal(bean, writer);

        return writer.toString();
    }

    public static <T> T toBean(String xml, Class<T> clazz) throws JAXBException, SAXException, IOException, ParserConfigurationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(new ByteArrayInputStream(xml.getBytes(ENCODING)));
        String schemaLocation = doc.getElementsByTagName("Message").item(0).getAttributes().getNamedItem("xsi:schemaLocation").getNodeValue();
        String xsd = schemaLocation.split("\\s+")[1];

        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        File file = new File(request.getSession().getServletContext().getRealPath("/") + "xsd/" + xsd);
        Schema schema = schemaFactory.newSchema(file);
        // unmarshaller.setSchema(schema);
        Validator validator = schema.newValidator();
        InputSource inputSource = new InputSource(new StringReader(xml));
        Source source = new SAXSource(inputSource);
        validator.validate(source);

        JAXBContext context = JAXBContext.newInstance(clazz);
        Unmarshaller um = context.createUnmarshaller();

        T result = (T) um.unmarshal(doc);

        return result;
    }

    public static org.dom4j.Document parseDoc(String xml) throws ParserConfigurationException, IOException, SAXException, DocumentException {
        return DocumentHelper.parseText(xml);
    }

    public static String getNodeValue(org.dom4j.Document doc, String node) {
        Element root = doc.getRootElement();
        String nsUri = root.getNamespaceURI();
        Map nsMap = new HashMap();
        nsMap.put("NS", nsUri);
        XPath mesXpath = doc.createXPath(node);
        mesXpath.setNamespaceURIs(nsMap);
        List<Node> mesList = mesXpath.selectNodes(doc);

        if (mesList.size() == 0) {
            return "";
        }

        return ((Node) mesList.get(0)).getText();
    }

    public static void reponse(String responseXml, HttpServletResponse response) {
        OutputStream os = null;
        try {
            response.setContentType("text/plain;charset=UTF-8");
            os = response.getOutputStream();
            os.write(responseXml.getBytes("utf-8"));
            os.flush();
            os.close();
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    private static <T> String getCustSendPath(T bean) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, WebserviceException {

        String customeCode = BeanUtils.getProperty(bean, "customeCode");
        if("4300".equals(customeCode))
        {
            return JINAN_CUST_TRANS_ID;
        }

        if("4200".equals(customeCode))
        {
            return QINGDAO_CUST_TRANS_ID;
        }

        throw new WebserviceException("不支持该关区代码:" + customeCode);
    }
}
 